/**
 * 滑动条组件基类
 * ibio-develop
 * 2009-3-2 21:42
 */
package com.ibio8.components.helpers {
	import flash.display.MovieClip;
	import flash.geom.Rectangle;
	import flash.events.MouseEvent;
	import flash.events.Event;
	/**
	 * 滑动条组件基类。
	 * 
	 * <p>
	 * 滑动条组件基类。通常由 Flash IDE 库中的 MC 继承此类。通常用于
	 * 播放器的进度显示。
	 * 此滑动条包括：加载进度条、播放进度条和拖动手柄。
	 * </p>
	 */
	public class BaseSlideBar extends MovieClip {
		/** @private **/
		protected var m_isVertical:Boolean = false;
		/** @private **/
		protected var m_container:MovieClip;
		/** @private **/
		protected var m_bar:MovieClip;
		/** @private **/
		protected var m_bg:MovieClip;
		/** @private **/
		protected var m_followBg:MovieClip;
		/** @private **/
		protected var m_clickDoLater:Function;
		/** @private **/
		protected var m_clickDoLaterParams:Array;
		/** @private **/
		protected var m_distance:Number;
		/** @private **/
		protected var m_currRatio:Number;
		/** @private **/
		protected var m_isLive:Boolean;
		/** @private **/
		protected var m_oldBarX:Number;
		/** @private **/
		protected var m_oldBarY:Number;
		/** @private **/
		protected var m_isDraging:Boolean = false;
		/** @private **/
		protected var m_bgRange:Number;
		/** @private **/
		protected var m_followBgW:Number;
		/** @private **/
		protected var m_followBgH:Number;
		
		/**
		 * 构造函数
		 * @param	bar			拖动条（String/MovieClip）
		 * @param	followBg	跟随背景（String/MovieClip）
		 * @param	bg			背景（String/MovieClip）
		 * @param	container	当前库里的 MC(MovieClip，配合 MCScrollBar 使用)
		 */
		function BaseSlideBar(bar:Object, followBg:Object, bg:Object, container:MovieClip = null) {
			/**
			 * 如果是直接 new BaseSlideBar，这里没有直接 m_container[bar]
			 * 是因为有可能 bar 会有扩展。
			 */
			//如果是继承库里的 MC
			if (container) {
				m_container = container;
				m_bar = m_container[bar];
				m_followBg = m_container[followBg];
				m_bg = m_container[bg];
			}else {
				m_container = bar.parent;
				m_bar = bar as MovieClip;
				m_followBg = followBg as MovieClip;
				m_bg = bg as MovieClip;
			}
			m_bar.buttonMode = true;
			m_followBg.mouseEnabled = false;
			m_bar.addEventListener(MouseEvent.MOUSE_DOWN, barPressHandler);
			m_bg.addEventListener(MouseEvent.MOUSE_DOWN, bgPressHandler);
			m_container.addEventListener(Event.ADDED_TO_STAGE, onContainerAddedHandler);
			m_container.addEventListener(Event.REMOVED_FROM_STAGE, onContainerRemovedHandler);
			m_oldBarX = m_bar.x;
			m_oldBarY = m_bar.y;
			m_followBgW = m_followBg.width;
			m_followBgH = m_followBg.height;
			setSize(m_bg.width, m_bg.height);
			initSize();
		}
		
		/**
		 * 改变 scroll bar 的大小，需要在每次 resize 的时候调用一次
		 * @param	width	新的宽度
		 * @param	height	新的高度
		 */
		public function setSize(width:Number, height:Number):void {
			if (m_isVertical) {
				m_bgRange = height;
			}else {
				m_bgRange = width;
			}
		}
		
		/**
		 * 设置bar当前的位置(0-1)
		 */
		public function set barRatio(ratio:Number):void {
			if (m_isDraging || (ratio < 0) || (ratio > 1)) {
				return;
			}
			m_currRatio = ratio;
			if (m_isVertical) {
				//因为m_bg有可能时刻变化，所以以m_bgRange来取总长度
				m_bar.y = m_bg.y + m_currRatio * (m_bgRange - m_bar.height);
			}else {
				m_bar.x = m_bg.x + m_currRatio * (m_bgRange - m_bar.width);
			}
			changeFollowBgPos();
		}
		
		/**
		 * 设置当前背景的位置(0-1)
		 * 因为在某些情况下，背景是不断变化的，例如 progress 的加载进度
		 */
		public function set bgRatio(ratio:Number):void {
			if ((ratio < 0) || (ratio > 1)) {
				return;
			}
			if (m_isVertical) {
				m_bg.height = ratio * m_bgRange;
			}else {
				m_bg.width = ratio * m_bgRange;
			}
			initSize();
		}
		
		public function get barRatio():Number {
			return m_currRatio;
		}
		
		/**
		 * 设置是否持续更新，还是等拖拽完毕之后在更新，
		 * 默认是等拖拽完毕之后再更新
		 */
		public function set isLive(value:Boolean):void {
			m_isLive = value;
		}
		
		/**
		 * true 是垂直滑动，默认是水平滑动
		 */
		public function set isVertical(value:Boolean):void {
			m_isVertical = value;
			//每次必须重置 size
			setSize(m_bg.width, m_bg.height);
			initSize();
		}
		
		/**
		 * 点击后的回调函数
		 * @param	clickMethod	回调函数
		 * @param	isLive		是否在bar移动过程中调用，默认不是
		 * @param	...rest		可选参数
		 */
		public function onClick(clickMethod:Function, isLive:Boolean = false, ...rest):void {
			m_isLive = isLive;
			m_clickDoLater = clickMethod;
			m_clickDoLaterParams = rest;
			if (m_clickDoLaterParams.length > 0) {
				//在第 0 个索引处增加一个位置，用来存放 m_currRatio
				m_clickDoLaterParams.splice(0, 0, 0);
			}
		}
		
		/** @private **/
		protected function initSize():void {
			if (m_isVertical) {
				m_distance = m_bg.height - m_bar.height;
				//将跟随背景的宽复原
				m_followBg.width = m_followBgW;
			}else {
				m_distance = m_bg.width - m_bar.width;
				m_followBg.height = m_followBgH;
			}
			//这里因为 m_bg 有可能时刻变化，所以有可能 < 0
			m_distance = (m_distance < 0) ? m_distance = 0 : m_distance;
			changeFollowBgPos();
		}
		
		/** @private **/
		protected function onMouseMoveHandler(e:MouseEvent):void {
			//在移动过程中不断更新
			if (m_isDraging) {
				e.updateAfterEvent();
				if (m_isLive) {
					if (m_isVertical) {
						changeBarPos(m_bar.y);
					}else {
						changeBarPos(m_bar.x);
					}
				}
				changeFollowBgPos();
			}
		}
		
		/** @private **/
		protected function barPressHandler(e:MouseEvent):void {
			m_bar.stage.addEventListener(MouseEvent.MOUSE_UP, onReleaseHandler);
			var rect:Rectangle;
			if (m_isVertical) {
				rect = new Rectangle(m_oldBarX, m_bg.y, 0, m_distance);
			}else {
				rect = new Rectangle(m_bg.x, m_oldBarY, m_distance, 0);
			}
			m_bar.startDrag(false, rect);
			m_isDraging = true;
		}
		
		/** @private **/
		protected function onReleaseHandler(e:MouseEvent):void {
			m_bar.stage.removeEventListener(MouseEvent.MOUSE_UP, onReleaseHandler);
			m_bar.stopDrag();
			if (m_isDraging) {
				if (m_isVertical) {
					changeBarPos(m_bar.y);
				}else {
					changeBarPos(m_bar.x);
				}
				changeFollowBgPos();
				m_isDraging = false;
			}
		}
		
		/** @private **/
		protected function bgPressHandler(e:MouseEvent):void {
			//如果是在 bg 上面或者从 bar上面释放鼠标 则执行更新
			if (m_bg.hitTestPoint(m_container.stage.mouseX, m_container.stage.mouseY)) {
				if (m_isVertical) {
					changeBarPos(m_container.mouseY, m_bar.height / 2);
				}else {
					changeBarPos(m_container.mouseX, m_bar.width / 2);
				}
				changeFollowBgPos();
			}
		}
		
		/** @private **/
		protected function changeBarPos(value:Number, delta:Number = 0, isIncrement:Boolean = false):void {
			var currRatio:Number;
			if (m_isVertical) {
				//是否是增量增加
				value = isIncrement ? (m_bar.y + value) : value;
				//delta表示在bar上偏移的量
				if (value <= (m_bg.y + delta)) {
					//注意：startDrag 移动有可能只对整数有效，所以这里用了 Math.round 来确保为整数
					m_bar.y = Math.round(m_bg.y);
				}else if (value >= (m_distance + delta + m_bg.y)) {
					m_bar.y = Math.round(m_distance + m_bg.y);
				}else {
					m_bar.y = Math.round(value - delta);
				}
				//因为m_bg有可能时刻变化，所以以 m_bgRange 来取总长度
				currRatio = (m_bar.y - m_bg.y) / (m_bgRange - m_bar.height);
			}else {
				if (value <= (m_bg.x + delta)) {
					m_bar.x = Math.round(m_bg.x);
				}else if (value >= (m_distance + delta + m_bg.x)) {
					m_bar.x = Math.round(m_distance + m_bg.x);
				}else {
					m_bar.x = Math.round(value - delta);
				}
				currRatio = (m_bar.x - m_bg.x) / (m_bgRange - m_bar.width);
			}
			//如果值未变，则跳出
			if (m_currRatio != currRatio) {
				m_currRatio = currRatio;
			}else {
				return;
			}
			//回调函数
			if (m_clickDoLater != null) {
				if (m_clickDoLaterParams.length == 0) {
					m_clickDoLater(m_currRatio);
				}else {
					m_clickDoLaterParams[0] = currRatio;
					m_clickDoLater.apply(null, m_clickDoLaterParams);
				}
			}
		}
		
		/** @private **/
		protected function changeFollowBgPos():void {
			var value:Number;
			if (m_isVertical) {
				value = m_bar.y + m_bar.height / 2 - m_bg.y;
				if (value < 0) {
					m_followBg.height = 0;
				}else if (value >= m_bg.height) {
					m_followBg.height = m_bg.height;
				}else {
					m_followBg.height = value;
				}
			}else {
				value = m_bar.x + m_bar.width / 2 - m_bg.x;
				if (value < 0) {
					m_followBg.width = 0;
				}else if (value > m_bg.width) {
					m_followBg.width = m_bg.width;
				}else {
					m_followBg.width = value;
				}
			}
		}
		
		/** @private **/
		protected function onContainerAddedHandler(e:Event):void {
			m_container.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMoveHandler);
			m_container.removeEventListener(Event.ADDED_TO_STAGE, onContainerAddedHandler);
		}
		
		/** @private **/
		protected function onContainerRemovedHandler(e:Event):void {
			m_bar.removeEventListener(MouseEvent.MOUSE_DOWN, barPressHandler);
			m_bg.removeEventListener(MouseEvent.MOUSE_DOWN, bgPressHandler);
			m_container.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMoveHandler);
			m_bar.stage.removeEventListener(MouseEvent.MOUSE_UP, onReleaseHandler);
			m_container.removeEventListener(Event.REMOVED_FROM_STAGE, onContainerRemovedHandler);
		}
	}
}